package com.tmall.testgen.common.util;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;

import com.tmall.testgen.common.util.bo.FieldClassAndValue;

/**
 * @author haojia
 * @date 2014-07-04
 */
public class Object2TreeMap {


	
	public static boolean isBasicType(Object o){
		if(o==null)
			return true;
		if(o instanceof String )
			return true;
		
		if(o instanceof Boolean )
			return true;
		if(o instanceof Byte )
			return true;
		if(o instanceof Short )
			return true;
		if(o instanceof Integer )
			return true;
		if(o instanceof Long )
			return true;
		if(o instanceof Float )
			return true;
		if(o instanceof Double )
			return true;
		if(o instanceof BigDecimal){
		    return true;
		}
		return false;
		
	}
	
	public static Class getClass(Class clazz){
			if(clazz==null)
				return null;
			String className=clazz.getName();
			if("int".equals(className))
				return Integer.class;
			
			if("boolean".equals(className) )
				return Boolean.class;
			if("byte".equals(className) )
				return Byte.class;
			if("short".equals(className) )
				return Short.class;
			if("long".equals(className) )
				return Long.class;
			if("float".equals(className) )
				return Float.class;
			if("double".equals(className) )
				return Double.class;
			
			return clazz;
			
	}
	
	private static String  getFieldName(boolean isSet,Method method, Map<String,FieldAndClass>fildClassMap){
		String methodName=method.getName();
	
		if(!isSet){
			
			if(methodName.startsWith("get")){
				if(fildClassMap.get(methodName.substring(3).toLowerCase())==null){
					return null;
				}
				return fildClassMap.get(methodName.substring(3).toLowerCase()).fieldName;
			}else if(methodName.startsWith("is")){
				if(fildClassMap.get(methodName.substring(2).toLowerCase())==null){
					return null;
				}
				return fildClassMap.get(methodName.substring(2).toLowerCase()).fieldName;
			}
			
		}else {
			if(!methodName.startsWith("set")){
				return null;
			}
			if(fildClassMap.get(methodName.substring(3).toLowerCase())==null){
				return null;
			}
			Class<?> fieldClass= fildClassMap.get(methodName.substring(3).toLowerCase()).type;
			
			
			if(method.getParameterTypes().length>1||method.getParameterTypes().length==0)
				return null;
			
			if(method.getParameterTypes()[0]!=fieldClass){
				return null;
			}
			return fildClassMap.get(methodName.substring(3).toLowerCase()).fieldName;
		}
		return null;
			
	}
	
		
	static class FieldAndClass{
		String fieldName;
		Class type;
	}
	
	/**
	 * 
	 * @param clazz
	 * @param value
	 * @param isSet 
	 * @return
	 */
	public static Map<String,FieldClassAndValue> getFieldMapFromClass(Class clazz,Object value,boolean isSet ){
		Map<String,FieldClassAndValue> result=new HashMap<String,FieldClassAndValue>();
		
			Class classTem=clazz;
	        Map<String,FieldAndClass>fildClassMap=new HashMap<String,FieldAndClass>();
	        for(; classTem != Object.class&&classTem!=null ; classTem = classTem.getSuperclass()) {  
	        	Field[] fields=classTem.getDeclaredFields();
	        	for(Field field:fields){
	        		field.setAccessible(true);
	        		FieldAndClass fc=new FieldAndClass();
	        		fc.fieldName=field.getName();
	        		fc.type=field.getType();
	        		fildClassMap.put(field.getName().toLowerCase(), fc);
	    		}
	        	
	        }  
	        classTem=clazz;
	        for(; classTem != Object.class&&classTem!=null  ; classTem = classTem.getSuperclass()) {  
	        	Method[] methods=classTem.getDeclaredMethods();
	        	
	        	
	        	
	        	for(Method m:methods){
	        		String fieldName=getFieldName(isSet,m, fildClassMap);
	        		if(fieldName==null)
	        			continue;
	        		
	        		FieldClassAndValue fav=new FieldClassAndValue();
		        	fav.setValue(fildClassMap.get(fieldName.toLowerCase()));
		        	result.put(fieldName, fav);
		        	
    				try{
    					//可能为空
    					Field f=classTem.getDeclaredField(fieldName);
    					f.setAccessible(true);
    					Object fv=f.get(value);
    					fav.setClazz(f.getType());
    					fav.setValue(fv);
    				}catch(Exception e){
    					fav.setClazz(fildClassMap.get(fieldName.toLowerCase()).type);
    				}
			    			
	        	}
	        	
	        }  
	        
	        return result;
	}
	/**
	 * 获取对应类型的map，仅一层
	 * @param obj
	 * @return
	 */
	public static Map<String,FieldClassAndValue> getMapFromObject(Object obj,boolean needNullValue){
		if(obj==null||isBasicType(obj))
			return null;
		
		Map<String,FieldClassAndValue> result=new LinkedHashMap<String,FieldClassAndValue>();
		
		
		if(obj instanceof Collection){
			Collection c=(Collection) obj;
			Iterator it=c.iterator();
			int i=0;
			while(it.hasNext()){
				Object tem=it.next();
				FieldClassAndValue fv=new FieldClassAndValue();
				fv.setClazz(tem.getClass());
				fv.setValue(tem);
				result.put(StringUtil.firstCharToLower(tem.getClass().getSimpleName())+"["+(i++)+"]", fv);
			}
			return result;
		}
		
		if(obj instanceof Map){
			Map m=(Map) obj;
			int i=0;
			for(Object key:m.keySet()){
				MapEntry entry=new MapEntry();
				entry.setKey(key);
				entry.setValue(m.get(key));
				
				FieldClassAndValue fv=new FieldClassAndValue();
				fv.setClazz(entry.getClass());
				fv.setValue(entry);
				result.put(StringUtil.firstCharToLower(entry.getClass().getSimpleName())+"["+(i++)+"]", fv);
			}
			return result;
		}
		
		
    	
        
        Class<?> clazz = obj.getClass() ;  
        Map<String,Class>fildNames=new HashMap<String,Class>();
        for(; clazz != Object.class ; clazz = clazz.getSuperclass()) {  
        	Field[] fields=clazz.getDeclaredFields();
        	for(Field field:fields){
        		fildNames.put(field.getName(),field.getType());
    		}
        	
        }  
        
        clazz = obj.getClass() ; 
        for(String fieldName :fildNames.keySet()){
            
            try{
                PropertyDescriptor pd = new PropertyDescriptor(fieldName,clazz);
                Method getMethod = pd.getReadMethod();//获得get方法
                Object o = getMethod.invoke(obj);//执行get方法返回一个Object
                
                FieldClassAndValue fcv=new FieldClassAndValue();
                fcv.setValue(o);
                try{
                    fcv.setClazz(o.getClass());  
                }catch(Exception e){
                    
                }
                if(fcv.getClazz()==null)
                    fcv.setClazz(fildNames.get(fieldName));
                
                
                if(o!=null){
                    result.put(fieldName, fcv);
                } else if(o==null&&needNullValue){
                    result.put(fieldName, fcv);
                }
                
                
            }catch(Exception e){
                
            }
        
        }
      
        return result;  
	}
}
